//go:build windows
// +build windows

package internal

import (
	"errors"
	"github.com/cakturk/go-netstat/netstat"
	"golang.org/x/sys/windows"
	"log"
	"syscall"
)

const processQueryInformation = windows.PROCESS_QUERY_LIMITED_INFORMATION

func GetSocketUid(port int64, network int8) (uid string, err error) {
	pid, err := findPidBYPort(uint16(port))
	if err != nil {
		return "", err
	}
	sid, err := getSidByPid(uint32(pid))
	if err != nil {
		return "", err
	}

	return sid, nil
}

func getSidByPid(pid uint32) (string, error) {
	c, err := windows.OpenProcess(processQueryInformation, false, pid)
	if err != nil {
		log.Println(err)
		return "", err
	}
	defer windows.CloseHandle(c)

	var token syscall.Token
	err = syscall.OpenProcessToken(syscall.Handle(c), syscall.TOKEN_QUERY, &token)
	if err != nil {
		log.Println(err)
		return "", err
	}
	defer token.Close()
	tokenUser, err := token.GetTokenUser()
	if err != nil {
		log.Println(err)
		return "", err
	}

	//username, domain, _, err := tokenUser.User.Sid.LookupAccount("")
	sid, err := tokenUser.User.Sid.String()
	if err != nil {
		log.Println(err)
		return "", err
	}

	return sid, nil
	//return domain + "\\" + username + "\\" + sid, err

}

func findPidBYPort(Port uint16) (int, error) {
	// get only Established TCP sockets
	tabs, err := netstat.TCPSocks(func(s *netstat.SockTabEntry) bool {
		return s.State == netstat.Established
	})
	if err != nil {
		log.Println("TPS", err)
		return 0, err
	}

	for _, e := range tabs {
		if e.LocalAddr.Port == Port {
			//fmt.Printf("%v\n%+v\n", e.Process.Pid, e.Process.Name)
			return e.Process.Pid, nil
		}

	}
	return 0, errors.New("not find")
}
